﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using GraphGeneric;
using System.Windows;
using System.Windows.Media;

namespace GraphGenericTestApp
{
    public class GraphCanvas : Canvas
    {
        public GraphCanvas()
            : base()
        {
            m_graph = new DirectedGraph();
            m_graph.AddNode("Saul");
            m_graph.AddNode("Abinadab");
            m_graph.AddNode("Eshbaal");
            m_graph.AddNode("Ish-bosheth");
            m_graph.AddNode("Malchi-shua");
            m_graph.AddNode("Ahinoam");
            m_graph.AddNode("Rizpah");
            m_graph.AddNode("Jonathan");
            m_graph.AddNode("Ishvi");
            m_graph.AddNode("Merab");
            m_graph.AddNode("Michal");
            m_graph.AddNode("David");
            m_graph.AddNode("Armoni");
            m_graph.AddNode("Mephibosheth");
            m_graph.AddNode("Mephibosheth2");
            m_graph.AddNode("Ziba");
            m_graph.AddNode("Kish");
            m_graph.AddNode("Abner");
            m_graph.AddNode("Ner");

            foreach (var node in m_graph.AllNodes)
            {
                if (node.Value != "Saul")
                {
                    m_graph.AddEdge("Saul", node.Value);
                    m_graph.AddEdge(node.Value, "Saul");
                }
            }

            m_graph.AddEdge("Rizpah", "Armoni");
            m_graph.AddEdge("Armoni", "Rizpah");
            m_graph.AddEdge("Rizpah", "Mephibosheth");
            m_graph.AddEdge("Mephibosheth", "Rizpah");
            m_graph.AddEdge("Jonathan", "Mephibosheth2");
            m_graph.AddEdge("Mephibosheth2", "Jonathan");
            m_graph.AddEdge("Mephibosheth2", "Ziba");
            m_graph.AddEdge("Ziba", "Mephibosheth2");
            m_graph.AddEdge("Michal", "David");
            m_graph.AddEdge("David", "Michal");
            m_graph.AddEdge("Ner", "Abner");
            m_graph.AddEdge("Abner", "Ner");
            m_graph.AddEdge("Ner", "Kish");
            m_graph.AddEdge("Kish", "Ner");


        }
        public DirectedGraph Graph
        {
            get { return m_graph; }
            set { m_graph = value; }
        }

        public Node RootNode
        {
            get { return m_rootNode; }
            set
            {
                if (m_rootNode != value)
                {
                    CreateVisualsFromRoot(m_rootNode, value, 1);

                    m_rootNode = value;
                    PositionNodes();

                }
            }
        }
        public double Scale
        {
            get { return m_scale; }
            set
            {
                if (m_scale != value)
                {
                    m_scale = value;
                    RenderTransform = new ScaleTransform(m_scale, m_scale);
                }
            }
        }
        private void PositionNodes()
        {
            if (m_rootNode == null)
                return;

            var visualRoot = m_nodeToVisual[m_rootNode];

            var visualChildren = from edge in m_rootNode.Edges
                                 select m_nodeToVisual[edge.ToNode as Node];

            // move the root node to the center
            visualRoot.Location = new Point(
                ActualWidth * 0.5 - visualRoot.ActualWidth * 0.5,
                ActualHeight * 0.5 - visualRoot.ActualHeight * 0.5);

            Random rand = new Random();
            foreach (var node in visualChildren)
            {
                // move each child node to a random location
                // TODO: the positioning algorithm will go here
                node.Location = new Point(
                    ActualWidth * rand.NextDouble() - node.ActualWidth / 2,
                    ActualHeight * rand.NextDouble() - node.ActualHeight);
            }
        }
        private void CreateVisualsFromRoot(Node oldRoot, Node newRoot, int level)
        {
            if (newRoot == null)
            {
                Children.Clear();
                m_nodeToVisual.Clear();
                //m_edgeToVisual.Clear();
            }
            else if (oldRoot == null)
            {
                Children.Clear();
                m_nodeToVisual.Clear();
                //m_edgeToVisual.Clear();

                AddVisualNode(newRoot);
                CreateAdjacentVisualNodes(newRoot, level);
            }
            else
            {
                //Children.Clear();
                //m_nodeToVisual.Clear();
                //m_edgeToVisual.Clear();

                //AddVisualNode(newRoot);
                //CreateAdjacentVisualNodes(newRoot, level);
                var nodesToAxe =
                    from oldEdge in oldRoot.Edges
                    let newChildren =
                       from e in newRoot.Edges
                       select e.ToNode
                    where !newChildren.Contains(oldEdge.ToNode) && oldEdge.ToNode.Value != newRoot.Value
                    select oldEdge.ToNode as Node;

                foreach (var node in nodesToAxe)
                {
                    var visual = m_nodeToVisual[node];
                    Children.Remove(visual);
                    m_nodeToVisual.Remove(node);
                }





            }

        }
        private void CreateAdjacentVisualNodes(Node node, int level)
        {
            if (level == 0)
                return;

            NodeCanvas nodeVisual = m_nodeToVisual[node];
            foreach (Edge edge in node.Edges)
            {
                AddVisualNode(edge.ToNode as Node);
                AddVisualEdge(edge as Edge);
                CreateAdjacentVisualNodes(edge.ToNode as Node, level - 1);
            }
        }
        private void AddVisualNode(Node node)
        {
            if (!m_nodeToVisual.ContainsKey(node))
            {
                NodeCanvas nodeVisual = new NodeCanvas(node, this);
                m_nodeToVisual.Add(node, nodeVisual);
                Children.Add(nodeVisual);
            }
        }
        private void AddVisualEdge(Edge edge)
        {
            //if (!m_edgeToVisual.ContainsKey(edge))
            //{
            //    EdgeCanvas edgeVisual = new EdgeCanvas(edge);
            //    m_edgeToVisual.Add(edge, edgeVisual);
            //    Children.Add(edgeVisual);
            //}
        }

        private DirectedGraph m_graph;
        private Node m_rootNode;
        private Dictionary<Node, NodeCanvas> m_nodeToVisual = new Dictionary<Node, NodeCanvas>();
        //private Dictionary<Edge, EdgeCanvas> m_edgeToVisual = new Dictionary<Edge, EdgeCanvas>();

        private double m_scale;
    }
}
